package system.config.aliyun.oss;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.aliyun.sdk.service.sts20150401.models.AssumeRoleResponseBody;
import common.config.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import system.config.aliyun.ram.AssumeRoleService;
import system.model.response.GenerateCredentialsResponse;

import javax.annotation.Resource;
import java.util.List;

/**
 * 阿里云OSS操作类
 *
 * @author 米泽鹏
 * @since 2024/1/12
 */
@Service
@Slf4j
public class OssService {

	@Value("${aliyun.oss.region}")
	private String region;
	@Value("${aliyun.oss.endpoint}")
	private String endpoint;
	@Value("${aliyun.oss.bucketName}")
	private String bucketName;
	@Value("${aliyun.oss.putObjectRoleArn}")
	private String putObjectRoleArn;
	@Value("${aliyun.oss.putObjectRoleSessionName}")
	private String putObjectRoleSessionName;
	@Value("${aliyun.oss.putObjectRoleDurationSeconds}")
	private Long putObjectRoleDurationSeconds;
	@Value("${aliyun.ram.ossAdminAccessKeyId}")
	private String accessKeyId;
	@Value("${aliyun.ram.ossAdminAccessKeySecret}")
	private String accessKeySecret;

	@Resource
	private AssumeRoleService assumeRoleService;

	public GenerateCredentialsResponse generateCredentialsForUpload() {
		AssumeRoleResponseBody.Credentials credentials = assumeRoleService.generateCredentials(putObjectRoleArn, putObjectRoleSessionName, putObjectRoleDurationSeconds);
		return buildGenerateCredentialsResponse(credentials);
	}

	private GenerateCredentialsResponse buildGenerateCredentialsResponse(AssumeRoleResponseBody.Credentials credentials) {
		GenerateCredentialsResponse response = new GenerateCredentialsResponse();
		response.setAccessKeyId(credentials.getAccessKeyId());
		response.setAccessKeySecret(credentials.getAccessKeySecret());
		response.setSecurityToken(credentials.getSecurityToken());
		response.setExpiration(credentials.getExpiration());
		response.setRegion(region);
		response.setBucket(bucketName);
		return response;
	}

	/**
	 * 查询多个文件
	 *
	 * @param bucketName bucket名称
	 * @param prefix     文件路径前缀
	 */
	public ListObjectsV2Result listObjects(String bucketName, String prefix) {
		// 创建OSSClient实例
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
		try {
			ListObjectsV2Result result = ossClient.listObjectsV2(bucketName, prefix);
			if (result.getResponse() != null && StrUtil.isNotBlank(result.getResponse().getErrorResponseAsString())) {
				log.error(result.getResponse().getErrorResponseAsString());
			}
			return result;
		} catch (Throwable throwable) {
			log.error("OSS查询多个文件出现异常");
			throw new CustomException(throwable);
		} finally {
			if (ossClient != null) {
				ossClient.shutdown();
			}
		}
	}

	/**
	 * 复制文件
	 *
	 * @param sourceBucketName      源bucket
	 * @param sourceKey             源文件路径
	 * @param destinationBucketName 目标bucket
	 * @param destinationKey        目标文件路径
	 */
	public void copyObject(String sourceBucketName, String sourceKey, String destinationBucketName, String destinationKey) {
		// 创建OSSClient实例
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
		try {
			CopyObjectResult result = ossClient.copyObject(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
			if (result.getResponse() != null && StrUtil.isNotBlank(result.getResponse().getErrorResponseAsString())) {
				log.error(result.getResponse().getErrorResponseAsString());
			}
		} catch (Throwable throwable) {
			log.error("OSS复制文件出现异常");
			throw new CustomException(throwable);
		} finally {
			if (ossClient != null) {
				ossClient.shutdown();
			}
		}
	}

	/**
	 * 复制文件
	 *
	 * @param copyObjectRequest 复制文件请求
	 */
	public void copyObject(CopyObjectRequest copyObjectRequest) {
		// 创建OSSClient实例
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
		try {
			CopyObjectResult result = ossClient.copyObject(copyObjectRequest);
			if (result.getResponse() != null && StrUtil.isNotBlank(result.getResponse().getErrorResponseAsString())) {
				log.error(result.getResponse().getErrorResponseAsString());
			}
		} catch (Throwable throwable) {
			log.error("OSS复制文件出现异常");
			throw new CustomException(throwable);
		} finally {
			if (ossClient != null) {
				ossClient.shutdown();
			}
		}
	}

	/**
	 * 删除单个文件
	 * oss删除文件是根据文件完成路径删除的，但文件完整路径中不能包含Bucket名称
	 * 比如文件URL为：https://satisfactory.oss-cn-beijing.aliyuncs.com/2022/08/abc.jpg
	 * 则filePath就是：2022/08/abc.jpg
	 *
	 * @param bucketName bucket名称
	 * @param filePath   文件路径
	 */
	public void deleteFile(String bucketName, String filePath) {
		if (StrUtil.isBlank(bucketName)) {
			throw new IllegalArgumentException("bucketName不能为空");
		}
		if (StrUtil.isBlank(filePath)) {
			throw new IllegalArgumentException("filePath不能为空");
		}
		// 创建OSSClient实例
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
		try {
			VoidResult result = ossClient.deleteObject(bucketName, filePath);
			if (result.getResponse() != null && StrUtil.isNotBlank(result.getResponse().getErrorResponseAsString())) {
				log.error(result.getResponse().getErrorResponseAsString());
			}
		} catch (Throwable throwable) {
			log.error("OSS删除文件出现异常");
			throw new CustomException(throwable);
		} finally {
			if (ossClient != null) {
				ossClient.shutdown();
			}
		}
	}

	/**
	 * 删除多个文件
	 *
	 * @param bucketName   bucket名称
	 * @param filePathList 文件路径列表
	 */
	public void deleteFiles(String bucketName, List<String> filePathList) {
		if (StrUtil.isBlank(bucketName)) {
			throw new IllegalArgumentException("bucketName不能为空");
		}
		if (CollUtil.isEmpty(filePathList)) {
			throw new IllegalArgumentException("filePathList不能为空");
		}
		// 创建OSSClient实例
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
		try {
			DeleteObjectsRequest request = new DeleteObjectsRequest(bucketName);
			request.setKeys(filePathList);
			DeleteObjectsResult result = ossClient.deleteObjects(request);
			if (result.getResponse() != null && StrUtil.isNotBlank(result.getResponse().getErrorResponseAsString())) {
				log.error(result.getResponse().getErrorResponseAsString());
			}
		} catch (Throwable throwable) {
			log.error("OSS删除文件出现异常");
			throw new CustomException(throwable);
		} finally {
			if (ossClient != null) {
				ossClient.shutdown();
			}
		}
	}

}
